package org.game.plugin.event;

import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.cfg.EventConditionCfg;
import org.cfg.cache.EventConditionCfgCache;
import org.constant.TaskConstant;
import org.game.constant.GameConstant;
import org.game.db.bean.Player;
import org.game.db.bean.Task;
import org.game.manager.TaskManager;
import org.game.module.event.EventSource;
import org.game.protobuf.s2c.S2CShareMsg.ChangeType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.collect.Maps;
import com.jfinal.plugin.IPlugin;
import com.sojoys.artifact.build.data.base.BasePojo;
import com.sojoys.artifact.manager.PropManager;
import com.xiaoleilu.hutool.util.ClassUtil;

/**
 * Event 插件
 * @author SandKing
 *
 */

@SuppressWarnings({ "rawtypes", "unused" })
public class GameEventPlugin implements IPlugin{
	
	static final Logger log = LoggerFactory.getLogger(GameEventPlugin.class);
	
	/** 事件处理器 */
	private static CopyOnWriteArrayList<GameEventHandler> eventHandlers = new CopyOnWriteArrayList<GameEventHandler>();
	
	/** 事件类型监听器 */
	private static ConcurrentHashMap<Integer,GameEventListener> eventListeners = new ConcurrentHashMap<Integer,GameEventListener>();
	
	/** 线程池 */
	static ExecutorService executor = Executors.newFixedThreadPool(4);
	
	private static boolean RUNING = false;
	/**
	 * 同步提交一个事件
	 */
	public static void syncSubmit(GameEvent event){
		if (!RUNING) {
			log.warn("Artifact EventPlugin Not Runing");
		}
		if (event.out == null) {
			event.out = Maps.newHashMap();
		}
		handler(event);
	}
	
	/**
	 * 异步提交一个事件
	 */
	public static void asynSubmit(GameEvent event){
		if (!RUNING) {
			log.warn("Artifact EventPlugin Not Runing");
		}
		executor.execute(() -> {
			handler(event);
		});
	}
	
	/**
	 * 初始化事件条件
	 * @param source
	 * @return
	 */
	public static void eventConditionInit(Player player, GameEventVector vector,int conditionId, Map params,int process,int maxProcess) {
		if (!RUNING) {
			log.warn("Artifact EventPlugin Not Runing");
		}
		
		EventConditionCfg eventConditionCfg = EventConditionCfgCache.me().getById(conditionId);
		if (eventConditionCfg == null) {
			log.error("not fond eventConditionId {}",conditionId);
			return;
		}
		// 继承进度
		if (process >= maxProcess) {
			vector.trigger(maxProcess);
			return;
		}
		
		// 如该条件不需要检查历史数据,则不进行条件初始化
		if (!eventConditionCfg.getHistory()) {
			return;
		}
		
		int eventId = eventConditionCfg.getEventId();
		GameEventStack eventStack = new GameEventStack(eventId, conditionId, params, process , maxProcess, false);
		GameEventListener listener = eventListeners.get(eventStack.getEventId());
		if (listener==null) {
			log.error("not fond eventId {}",eventStack.getEventId());
			return;
		}
		// 执行初始化
		listener.initEventCondition(player, eventStack);
		

			
		// 如果有条件进度被修改了
		if (eventStack.isTrigger(vector, eventStack.getProgress())) {
			vector.trigger(maxProcess);
		}
	}

	/**
	 * 事件处理器调度
	 * @param event
	 */
	private static void handler(GameEvent event) {
		Iterator<GameEventHandler> iterator = eventHandlers.iterator();
		GameEventListener eventListener = eventListeners.get(event.getEventType());
		if (eventListener == null) {
			log.warn("not fond eventListener = " + event.getEventType());
		}
		while (iterator.hasNext()) {
			GameEventHandler eventHandler = iterator.next();
			eventHandler.onEvent(eventListener,event);
		}
	}
	
	/**
	 * 注册事件处理器
	 */
	@SuppressWarnings("rawtypes")
	private void registryHandler(){
		eventHandlers.clear();
		log.debug("----------------------------Scan Event Handler Begin----------------------------");
		Set<Class<?>> scanClasses = ClassUtil.scanPackageBySuper(PropManager.get(GameConstant.SCAN_EVENT_HANDLER),GameEventHandler.class);
		for (Class scanClass : scanClasses) {
			if (scanClass.isInterface()) {
				continue;
			}
			Object impl = ClassUtil.newInstance(scanClass);
			eventHandlers.add((GameEventHandler) impl);
			log.debug("Registry EventHandler：{}",impl.getClass().getName());
		}
		log.debug("----------------------------Scan Event Handler End----------------------------");
	}
	
	/**
	 * 注册事件监听器
	 */
	private void registryListener(){
		eventListeners.clear();
		log.debug("----------------------------Scan Event Listener Begin----------------------------");
		Set<Class<?>> scanClasses = ClassUtil.scanPackageBySuper(PropManager.get(GameConstant.SCAN_EVENT_LISTENER),GameEventListener.class);
		for (Class<?> scanClass : scanClasses) {
			if (scanClass.isInterface()) {
				continue;
			}
			GameEventType annotation = scanClass.getAnnotation(GameEventType.class);
			int eventType = annotation.value();
			Object impl = ClassUtil.newInstance(scanClass);
			eventListeners.put(eventType, (GameEventListener) impl);
			log.debug("Registry EventListener：{} -> {}",eventType , impl.getClass().getName());
		}
		log.debug("----------------------------Scan Event Listener End----------------------------");
	}

	@Override
	public boolean start() {
		if (!RUNING) {
			registryHandler();
			registryListener();
			RUNING = true;
		}
		return true;
	}

	@Override
	public boolean stop() {
		executor.shutdown();
		RUNING = false;
		return true;
	}
}
